
package com.scs.application.modules.order.controller;


import cn.afterturn.easypoi.entity.ImageEntity;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelXorHtmlUtil;
import cn.afterturn.easypoi.excel.entity.ExcelToHtmlParams;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.core.exceptions.ExportException;
import com.scs.application.core.exceptions.ImportException;
import com.scs.application.core.model.CommonResult;
import com.scs.application.core.model.ImportResult;
import com.scs.application.core.model.PageResult;
import com.scs.application.core.model.RestResult;
import com.scs.application.core.mvc.controller.CrudController;
import com.scs.application.core.mvc.controller.ImAndExAbleController;
import com.scs.application.core.pdf.PdfExportUtils;
import com.scs.application.core.pdf.entity.PdfExportParams;
import com.scs.application.core.pdf.enums.PdfPageDirection;
import com.scs.application.core.pdf.enums.SpacingMode;
import com.scs.application.core.utils.*;
import com.scs.application.enums.BasePrintBusType;
import com.scs.application.modules.base.entity.*;
import com.scs.application.modules.base.request.PrintTemplateQueryRequest;
import com.scs.application.modules.base.service.*;
import com.scs.application.modules.base.vo.PrintTemplateVO;
import com.scs.application.modules.order.consts.MatrTypeCodeConsts;
import com.scs.application.modules.order.dto.CloseDeliveryDTO;
import com.scs.application.modules.order.dto.CloseOrderDto;
import com.scs.application.modules.order.dto.ExcelDeliveryDTO;
import com.scs.application.modules.order.entity.*;
import com.scs.application.modules.order.request.DeliveryQueryRequest;
import com.scs.application.modules.order.service.DeliveryItemService;
import com.scs.application.modules.order.service.DeliveryItemSnService;
import com.scs.application.modules.order.service.DeliveryService;
import com.scs.application.modules.order.vo.ExcelDeliveryVO;
import lombok.AllArgsConstructor;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 发货单 controller
 *
 */
@AllArgsConstructor
@RestController
@SuppressWarnings("all")
@RequestMapping("/order/deliverys")
public class DeliveryController extends CrudController<Delivery, String, DeliveryService> implements ImAndExAbleController<DeliveryQueryRequest> {

    private final DeliveryItemService deliveryItemService;

    private final HospitalService hospitalService;

    private final HospitalWarehouseService hospitalWarehouseService;

    private final HospitalConfigService hospitalConfigService;

    private final MaterialSpecService materialSpecService;

    private final HospitalMaterialService hospitalMaterialService;

    @Autowired
    private SupplierService supplierService;

    @Autowired
    @Lazy
    private  DeliveryItemSnService deliveryItemSnService;

    @Autowired
    private PrintTemplateService printTemplateService;

    @PostMapping
    public CommonResult add(@RequestBody @Valid Delivery entity) {
        //第二个参数是为点击发货生成待发货单调用saveDeliverys用的
        boolean bSave = service.saveDeliverys(entity, null);
        return bSave ? CommonResult.ok("新增成功", entity) : CommonResult.error("新增失败");
    }

    private void fillPage(IPage<Delivery> page) {
        if (page.getTotal() > 0) {
            List<String> warehouseidList = page.getRecords().stream().filter(item -> StringUtils.isNotBlank(item.getWarehouseId())).map(Delivery::getWarehouseId).distinct().collect(Collectors.toList());
            Map<String, HospitalWarehouse> warehouseById = null;
            if (ObjectUtil.length(warehouseidList) > 0) {
                warehouseById = hospitalWarehouseService.list(Wrappers.<HospitalWarehouse>query().in("id",warehouseidList)).stream().collect(Collectors.toMap(HospitalWarehouse::getId, item -> item));
            }

            for (Delivery delivery : page.getRecords()) {
                //发货人
                delivery.setSendUser(UserUtils.getSupplier().getContactor());
                //发货人联系电话
                delivery.setSendMobile(UserUtils.getSupplier().getMobile());
                //发货地址
                delivery.setSendAddress(UserUtils.getSupplier().getAddress());

                if (warehouseById != null && StringUtils.isNotBlank(delivery.getWarehouseId()) && warehouseById.containsKey(delivery.getWarehouseId())) {
                    delivery.setReceiveUser(warehouseById.get(delivery.getWarehouseId()).getReceiveUser());
                    delivery.setReceivePhone(warehouseById.get(delivery.getWarehouseId()).getReceivePhone());
                    delivery.setReceiveAddress(warehouseById.get(delivery.getWarehouseId()).getReceiveAddress());
                }
            }
        }
    }

    @GetMapping("/page")
    public PageResult page(DeliveryQueryRequest request) {
        IPage<Delivery> page = service.page(request);
        List<Delivery> deliveries = page.getRecords();
        //加入判断是否UDI必填
        List<HospitalConfig> hospitalConfigDTOS = hospitalConfigService.getAllHospitalConfigs();
        if (hospitalConfigDTOS != null && hospitalConfigDTOS.size() > 0) {
            for (Delivery delivery : deliveries) {
                hospitalConfigDTOS.stream()
                        .filter(config -> config.getHospitalId().equals(delivery.getHospitalId()))
                        .findFirst()
                        .ifPresent(config ->
                                delivery.setUdiNecessary(GlobalConsts.YES_STR.equals(config.getFlagDeliveryUdiNecessary())));

            }
        }

        fillPage(page);

        return PageResult.ok("查询成功", deliveries, page.getTotal());
    }

    @GetMapping("/list")
    public CommonResult list(DeliveryQueryRequest request) {
        List<Delivery> list = service.list(request);
        return CommonResult.ok("查询成功", list);
    }

    /**
     * @param id
     * @Description: 发货
     * @return: com.scs.application.core.model.CommonResult
     */
    @PostMapping("/{id}/delivery")
    public CommonResult delivery(@PathVariable("id") String id) {
        Delivery delivery = service.delivery(id);
        // 操作日志
        syslogSuccess(
                SysLog.moduleType.delivery,
                "发货",
                delivery.getId(),
                delivery.getCode(),
                UserUtils.currentUser().getNickname(),
                ""
        );


        return delivery != null ? CommonResult.ok(delivery.getMsgReturn(), delivery) : CommonResult.error("发货失败");
    }

    /**
     * @param id
     * @Description: 取消发货
     * @return: com.scs.application.core.model.CommonResult
     */
    @PostMapping("/{id}/cancel_delivery")
    public CommonResult cancelDelivery(@PathVariable("id") String id,@RequestBody CloseOrderDto dto) {

        boolean cancelDeliverBool = service.cancelDelivery(id);

        // 操作日志
        Delivery main = service.getById(id);
        if (main != null) {
            syslogSuccess(
                    SysLog.moduleType.delivery,
                    "取消发货",
                    main.getId(),
                    main.getCode(),
                    UserUtils.currentUser().getNickname(),
                    StrUtil.format("原因:{}",dto.getReason())
            );
        }

        return cancelDeliverBool ? CommonResult.ok("取消发货成功") : CommonResult.error("取消发货失败");
    }

    /**
     * @param id
     * @Description: 取消发货
     * @return: com.scs.application.core.model.CommonResult
     */
    @PostMapping("/{id}/clear_sn")
    public CommonResult clearSn(@PathVariable("id") String id,@RequestBody CloseOrderDto dto) {

        int count = deliveryItemSnService.count(Wrappers.<DeliveryItemSn>query().eq("delivery_id", id));
        deliveryItemSnService.remove(Wrappers.<DeliveryItemSn>query().eq("delivery_id", id));
        // 操作日志
        Delivery main = service.getById(id);
        if (main != null) {
            syslogSuccess(
                    SysLog.moduleType.delivery,
                    "清除标签",
                    main.getId(),
                    main.getCode(),
                    UserUtils.currentUser().getNickname(),
                    StrUtil.format("原因:{},清除标签数量{}",dto.getReason(),count)
            );
        }

        return CommonResult.ok("操作成功");
    }

    @GetMapping("/send_page")
    public PageResult sendPage(DeliveryQueryRequest request) {
        IPage<Delivery> page = service.sendPage(request);
        fillPage(page);
        return PageResult.ok("查询成功", page.getRecords(), page.getTotal());
    }

    @GetMapping("/all_delivery_page")
    public PageResult allDeliveryPage(DeliveryQueryRequest request) {
        if (UserUtils.isHospital()) {
            request.setHospitalId(UserUtils.getHospitalId());
        } else {
            request.setSupplierId(UserUtils.getSupplierId());
        }
        IPage page = service.allDeliveryPage(request);
        fillPage(page);
        return PageResult.ok("查询成功", page.getRecords(), page.getTotal());
    }

    /**
     * 关闭发货单
     *
     * @param dto
     * @return
     */
    @PostMapping("/close")
    public CommonResult closeDelivery(@RequestBody CloseDeliveryDTO dto) {
        service.closeDelivery(dto);
        return CommonResult.ok("作废成功");
    }

    /**
     * @param
     * @Description: 发货单压缩
     * @return: com.scs.application.core.model.CommonResult
     *//*
    @PostMapping("/{id}/zip_deliveryItem")
    public CommonResult zipDeliveryItem( @PathVariable(name = "id") String deliveryId) {
        DeliveryZip delivery= service.getDeliveryItemQrCodeString(deliveryId);
        return  CommonResult.ok("压缩成功",delivery);
    }*/
    @GetMapping("/{id}/deliveryTemplate")
    public CommonResult deliveryTemplate(@PathVariable(name = "id") String id, HttpServletResponse response) throws Exception {

        Delivery delivery = this.service.getById(id);

        TemplateExportParams params = new TemplateExportParams(
                "doc/送货单.xls");
        // 标题开始行
        params.setHeadingStartRow(3);
        // 标题行数
        params.setHeadingRows(1);

        ImageEntity image = new ImageEntity();
        //image.setRowspan(1);
        image.setColspan(2);
        image.setUrl("imgs/barcode.jpg");
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("hospitalName", delivery.getHospitalName());
        map.put("barcode", image);
        map.put("code", delivery.getCode());
        map.put("supplierName", delivery.getSupplierName());
        map.put("gmtDelivery", DateUtils.format(delivery.getGmtDelivery(), "yyyy-MM-dd HH:mm:ss"));
        map.put("poCode", delivery.getPoCode());
        map.put("orderAmount", delivery.getOrderAmount());
        map.put("deliveryAmount", delivery.getDeliveryAmount());

        List<DeliveryTemplateExportEntity> list = new ArrayList<DeliveryTemplateExportEntity>();
        List<DeliveryItem> deliveryItems = deliveryItemService.list(Wrappers.<DeliveryItem>query().eq("delivery_id", delivery.getId()));

        BeanUtils.copyProperties(deliveryItems, list, DeliveryTemplateExportEntity.class);
        response.setContentType("text/html;charset=UTF-8");

        // setDownloadParam("送货单.xlsx");
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             Workbook workbook = ExcelExportUtil.exportExcel(params, DeliveryTemplateExportEntity.class, list, map)
        ) {
            workbook.write(bos);
            workbook.close();
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());

            ExcelToHtmlParams params1 = new ExcelToHtmlParams(WorkbookFactory.create(bis), false, "yes");
//            response.getOutputStream().write(ExcelXorHtmlUtil.excelToHtml(params1).getBytes());
            String html = ExcelXorHtmlUtil.excelToHtml(params1);
            bis.close();
            return CommonResult.ok("生成成功", html);
        }

    }

    /**
     * @param
     * @Description: 发货单压缩
     * @return: com.scs.application.core.model.CommonResult
     */
    @PostMapping("/{id}/zip_deliveryItem")
    public CommonResult zipDeliveryItem(@PathVariable(name = "id") String deliveryId) {
        DeliveryZip delivery = service.getDeliveryItemQrCodeString(deliveryId);
        return CommonResult.ok("压缩成功", delivery);
    }

    /**
     * 发货单 导出数据
     */
    @Override
    public void excelExport(DeliveryQueryRequest request) {
        String fileName = "发货单信息" + DateUtils.format(DateUtils.now(), "yyyyMMddHHmmss") + ".xlsx";
        ExportParams params = PoiUtils.getDefaultExportParams("发货单导出信息", "发货单信息", true);
        request.setSupplierId(UserUtils.isSupplier() ? UserUtils.getSupplierId() : null);
        List<ExcelDeliveryVO> list = service.listExcel(request);
        List<ExcelDeliveryDTO> dtos = Lists.newArrayListWithCapacity(list.size());
        BeanUtils.copyProperties(list, dtos, ExcelDeliveryDTO.class);
        try {
            setDownloadParam(fileName);
            PoiUtils.exportExcel(response().getOutputStream(), params, ExcelDeliveryDTO.class, dtos);
        } catch (IOException e) {
            throw new ExportException("导出异常", e);
        }
    }

    /**
     * 发货单导出数据模板
     */
    @Override
    public void excelTemplate(DeliveryQueryRequest request) {
        String fileName = "发货单导入模板.xlsx";
        ExportParams params = PoiUtils.getDefaultExportParams("发货单导入模板", "发货单信息", true);
        params.setExclusions(new String[]{"错误行号", "错误信息", "送达地点名称", "是否寄售", "是否一物一码"});
        try {
            setDownloadParam(fileName);
            ExcelDeliveryDTO mockData = PoiUtils.mockData(ExcelDeliveryDTO.class);
            PoiUtils.exportExcel(response().getOutputStream(), params, ExcelDeliveryDTO.class, Lists.newArrayList(mockData));
        } catch (IOException e) {
            throw new ExportException("导出异常", e);
        }
    }

    /**
     * 发货单导入数据
     */
    @Override
    public CommonResult<ImportResult> excelImport(MultipartFile file) throws ImportException {
        return CommonResult.ok("导入成功", service.excelImport(file));
    }

    /**
     * PDF打印预览
     *
     * @param id
     * @param response
     */
    @GetMapping("/{id}/pdf-preview")
    public void pdfPreview(@PathVariable(name = "id") String id,
                           @RequestParam(name = "direction", required = false, defaultValue = "transverse") String direction,
                           @RequestParam(name = "spacingMode", required = false, defaultValue = "normal") String spacingMode,
                           @RequestParam(name = "pageSize", required = false, defaultValue = "A4") String pageSize,
                           @RequestParam(name = "perRowsOfGrid", required = false, defaultValue = "5") int perRowsOfGrid,
                           HttpServletResponse response) throws IOException {

        Delivery delivery = service.getById(id);
        if (delivery == null) {
            return;
        }
        if (StringUtils.isBlank(delivery.getRemark())) {
            delivery.setRemark("");
        }
        PdfPageDirection pageDirection = PdfPageDirection.of(direction);
        SpacingMode sMode = SpacingMode.of(spacingMode);
        //查询改医院是否配置自定义模板
        PrintTemplateVO iv = printTemplateService.findPrintTemplateVO(new PrintTemplateQueryRequest().setHospitalId(delivery.getHospitalId())
                .setBusType(BasePrintBusType.DELIVERY.getValue()).setThisPageSize(pageSize));
        String templateJson = null;
        if (iv.getId() != null) {
            /*for(Field f : delivery.getClass().getDeclaredFields()) {
                f.setAccessible(true);
                //判断字段是否为空，并且对象属性中的基本都会转为对象类型来判断
                    String name = f.getName();
                    if(f.get(f.getName()) == null){
                        f.set(name, "");
                }
            }*/
            if (delivery.getDemandDeptName() == null) {
                delivery.setDemandDeptName("");
            }
            templateJson = iv.getConfigJson();
        } else if (delivery.getMaterialTypeCode() != null && delivery.getMaterialTypeCode() == MatrTypeCodeConsts.REAGENT) {
            String path = String.format("print-template/delivery/reagent/%s.json", pageSize.toUpperCase());
            templateJson = FileUtils.readClassPathFileToString(path, "UTF-8");
        }  else {
            String path = String.format("print-template/delivery/%s.json", pageSize.toUpperCase());
            templateJson = FileUtils.readClassPathFileToString(path, "UTF-8");
        }
        /*if (StringUtils.isBlank(templateJson)) {
            throw new BusinessException("打印模板可能未配置，请联系系统管理员");
        }*/

        if (StringUtils.isNotBlank(delivery.getWarehouseId())) {
            HospitalWarehouse hospitalWarehouse = hospitalWarehouseService.getById(delivery.getWarehouseId());
            if (hospitalWarehouse != null) {
                delivery.setReceiveUser(hospitalWarehouse.getReceiveUser());
                delivery.setReceivePhone(hospitalWarehouse.getReceivePhone());
                delivery.setReceiveAddress(hospitalWarehouse.getReceiveAddress());
            }
        }

        Supplier supplier = supplierService.getById(delivery.getSupplierId());
        if (supplier != null) {
            //发货人
            delivery.setSendUser(supplier.getContactor());
            //发货人联系电话
            delivery.setSendMobile(supplier.getMobile());
            //发货地址
            delivery.setSendAddress(supplier.getAddress());
        }



        response.setContentType(MediaType.APPLICATION_PDF_VALUE);
        response.addHeader("Content-Disposition", String.format("filename=%s.pdf", URLEncoder.encode("送货单-" + delivery.getCode())));

        Map<String, Object> map = Maps.newHashMap();
        map.put("delivery", delivery);

        templateJson = FreeMarkers.renderString(templateJson, map);
        PdfExportParams exportParams = PdfExportParams.fromJson(templateJson);

        exportParams.setSpacingMode(sMode);
        exportParams.setPageDirection(pageDirection);
        exportParams.setPerRowsOfGrid(perRowsOfGrid);

        List<DeliveryItem> items = deliveryItemService.list(Wrappers.<DeliveryItem>query().eq("delivery_id", id));
        items.forEach(item -> {
            Double orderPrice = item.getPrice() * item.getOrderQty();
            item.setOrderPrice(BigDecimal.valueOf(orderPrice).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
            //打印时   如果批次字数太多，根据/强制换行
            item.setLot(getLongWord(item.getLot()));
            item.setManufacturerName(getLongWord(item.getManufacturerName()));
            item.setHasSunPurchaseCode(StringUtils.isBlank(item.getSunPurchaseCode()) ? "否" : "是");


            // 填充中标号
            if (StringUtils.isNotBlank(item.getMaterialCode())) {
                HospitalMaterial hospitalMaterial = hospitalMaterialService.getOne(Wrappers.<HospitalMaterial>query().eq("material_code",item.getMaterialCode()), false);
                if (hospitalMaterial != null) {
                    item.setBidNo(hospitalMaterial.getBidno());
                }
            }
        });
        exportParams.setGridData(items);
        PdfExportUtils.export(response.getOutputStream(), exportParams);
    }

    private String getLongWord(String strWords) {
        if (StringUtils.isBlank(strWords)) {
            return "";
        }
        if (strWords.length() > 10) {
            String strNewWords = "";
            for (int i = 0; i < strWords.length(); i++) {
                char word = strWords.charAt(i);
                if (i != 0 && word == '/') {
                    strNewWords += " " + strWords.charAt(i);
                } else if (Character.isUpperCase(word)) { //如果为大写的，也加个空格
                    strNewWords += " " + strWords.charAt(i);
                } else {
                    strNewWords += strWords.charAt(i);
                }
            }
            return strNewWords;
        }
        return strWords;
    }

    /***
     * @param id
     * @Description:  通用查找，单个
     */
    @GetMapping("/findByIdCommon")
    public RestResult findByIdCommon(@RequestParam("id") Serializable id) {
        Delivery entity = service.getById(id);
        if (entity == null) {
            return RestResult.error("数据查询失败<br>可能所操作数据已被删除，请刷新后重新尝试操作");
        }
        fillEntity(entity);
        return RestResult.ok("获取数据成功", entity);
    }

    /***
     * @param entity
     * @Description:  通用保存、更新
     */
    @PostMapping("/saveOrUpdateCommon")
    public RestResult saveOrUpdateCommon(@Valid @RequestBody Delivery entity) {
        boolean isOk = service.saveOrUpdate(entity);
        if (!isOk) {
            return RestResult.error("数据保存失败");
        }
        fillEntity(entity);
        return RestResult.ok("数据保存成功", entity);
    }

    private void fillEntity(Delivery entity) {
        // 填充发货信息
        Supplier sp =supplierService.getById(entity.getSupplierId());
        if (sp!= null) {
            //发货人
            entity.setSendUser(sp.getContactor());
            //发货人联系电话
            entity.setSendMobile(sp.getMobile());
            //发货地址
            entity.setSendAddress(sp.getAddress());
        }


        // 填充收货信息
        if (StringUtils.isNotBlank(entity.getWarehouseId())) {
            HospitalWarehouse hw = hospitalWarehouseService.getById(entity.getWarehouseId());
            if (hw!= null) {
                entity.setReceiveUser(hw.getReceiveUser());
                entity.setReceivePhone(hw.getReceivePhone());
                entity.setReceiveAddress(hw.getReceiveAddress());
            }
        }
    }

}
